package com.kayo.specimen.controller;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.google.code.kaptcha.Constants;
import com.kayo.specimen.annotion.CurrentUser;
import com.kayo.specimen.annotion.JsonParam;
import com.kayo.specimen.annotion.PagingParam;
import com.kayo.specimen.model.JsonResult;
import com.kayo.specimen.model.Role;
import com.kayo.specimen.model.User;
import com.kayo.specimen.model.view.UserView;
import com.kayo.specimen.service.RoleService;
import com.kayo.specimen.service.UserService;
import com.kayo.specimen.utility.CryptUtils;
import com.kayo.specimen.utility.PagingInfo;
import com.kayo.specimen.utility.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.thymeleaf.util.DateUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.stream.Collectors;

import static com.kayo.specimen.model.JsonResult.STATUS_ERROR;
import static com.kayo.specimen.model.JsonResult.STATUS_SUCCESS;


@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private RoleService roleService;

    @Autowired
    private UserService userService;

    @RequestMapping(value = {"/login", ""}, method = {RequestMethod.GET})
    public ModelAndView login() {
        return new ModelAndView("/views/user/login");
    }

    @RequestMapping(value = "/login", method = {RequestMethod.POST})
    public Object login(@NotEmpty String code, @NotEmpty String password, @NotEmpty String captcha, Boolean remember,
                        HttpServletRequest request, HttpServletResponse response) {
        String captchaFromSession = (String) request.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if (!captcha.equals(captchaFromSession))
            return JsonResult.error("验证码不正确");

        //用户认证信息
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(code, password, remember != null && remember);
        try {
            //进行验证，这里可以捕获异常，然后返回对应信息
            subject.login(usernamePasswordToken);
        } catch (AuthenticationException e) {
            return new JsonResult(STATUS_ERROR, e.getMessage());
        }

        return JsonResult.success();
    }

    @RequestMapping("/logout")
    public void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        SecurityUtils.getSecurityManager().logout(SecurityUtils.getSubject());
        response.sendRedirect("/user/login");
    }

    @RequestMapping("/forget")
    public ModelAndView forget() {
        return new ModelAndView("/views/user/forget");
    }

    @RequestMapping("/setPassword")
    public ModelAndView setPassword() {
        return new ModelAndView("/views/set/user/password");
    }

    @CacheEvict(value = "user",key = "#user.id")
    @RequestMapping(value = "/setPassword", method = RequestMethod.POST)
    public Object setPassword(@CurrentUser User user, String oldPassword, String newPassword) {
        if (!CryptUtils.encrypt(oldPassword).equals(user.getPassword()))
            return JsonResult.error("旧密码错误");

        if (!oldPassword.equals(newPassword))
            return JsonResult.error("新旧密码不匹配");

        user.setPassword(newPassword);
        userService.updateUsers(user);
        return JsonResult.success();
    }

    @RequiresPermissions("读取用户")
    @RequestMapping("/index")
    public ModelAndView index() {
        return new ModelAndView("/views/user/user/list");
    }

    @Cacheable(value = "user")
    @RequiresPermissions("读取用户")
    @RequestMapping("/list")
    public Object list(String code, String name, String email,@PagingParam PagingInfo pagingInfo) {
        PageHelper.startPage(pagingInfo.getPage(), pagingInfo.getLimit());
        List<UserView> users = userService.getUsers(code, name, email, pagingInfo.getOrderByClause());

        PageInfo<UserView> result = new PageInfo<>(users);
        return JsonResult.success(result);
    }

    @RequiresPermissions("更新用户")
    @RequestMapping(value = "/edit", method = RequestMethod.GET)
    public ModelAndView edit(String code) {
        List<UserView> users = userService.getUsers(code, null, null, null);
        List<Role> roles = roleService.getRoles(null,null,"id");
        ModelAndView modelAndView = new ModelAndView("/views/user/user/userform");
        modelAndView.addObject("user", users.get(0));
        modelAndView.addObject("roles",roles);

        return modelAndView;
    }

    @CachePut(value = "user")
    @Transactional
    @RequiresPermissions("更新用户")
    @RequestMapping(value = "/update", method = RequestMethod.POST)
    public Object update(@JsonParam("user")User user, @JsonParam("roles") String[] roles) throws NoSuchAlgorithmException {
        if (StringUtils.isNullOrEmpty(user.getId())) {
            userService.addUsers(user);
        } else
            userService.updateUsers(user);

        List<Role> grantedRoles = userService.getGrantedRoles(user.getId());
        String[] grantedRolesId = grantedRoles.stream().map(f -> f.getId()).collect(Collectors.toList()).toArray(new String[0]);
        userService.revokeRoles(user.getId(),grantedRolesId);

        userService.grantRoles(user.getId(), roles);
        return JsonResult.success();
    }

    @CacheEvict(value = "user")
    @RequiresPermissions("删除用户")
    @RequestMapping("/delete")
    public Object delete(@JsonParam String[] id) {
        userService.removeUsers(id);
        return JsonResult.success();
    }

    @RequiresPermissions("更新用户")
    @RequestMapping("/add")
    public ModelAndView add() {
        UserView user = new UserView();
        user.setEnabled(true);
        user.setCreateTime(DateUtils.createNow().getTime());
        user.setRoles(new ArrayList<>());
        List<Role> roles = roleService.getRoles(null,null,"id");
        ModelAndView modelAndView = new ModelAndView("/views/user/user/userform");
        modelAndView.addObject("user", user);
        modelAndView.addObject("roles",roles);
        return modelAndView;
    }
}
